package api

import (
	"ams/daemon/tcp"
	"ams/dao"
	"ams/service"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	log "github.com/sirupsen/logrus"
	"lib/http"
	"lib/structs/ams"
	"lib/utils"
	http2 "net/http"
	"strings"
	"time"
	"unicode"
)

var ChatApi = new(chatApi)

type chatApi struct {
}

func (api chatApi) Conn(c *gin.Context) {
	var UpGrader = websocket.Upgrader{
		CheckOrigin: func(r *http2.Request) bool {
			return true // 允许跨域（生产环境需限制）
		},
	}
	ws, err := UpGrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		http.BadWithErr(c, err)
		return
	}
	go func() {
		defer ws.Close()
		for {
			_, msg, err := ws.ReadMessage()
			if err != nil {
				log.Error("ReadMessage err:", err)
				break
			}
			var chatDto ams.ChatInDto
			err = json.Unmarshal(msg, &chatDto)
			if err != nil {
				err = service.DsService.WsWriteMessage(ws, "err", fmt.Sprintf("输入参数不正确，err:[%v],in:[%s]", err.Error(), msg))
				if err != nil {
					log.Error("WriteMessage err:", err)
				}
				continue
			}
			if chatDto.MsgType == "ping" {
				err = service.DsService.WsWriteMessage(ws, "ping", "pong")
				if err != nil {
					log.Error("WriteMessage err:", err)
				}
				continue
			}
			err = api.handleMsg(chatDto, ws)
			if err != nil {
				log.Error("handleMsg err:", err)
				err = service.DsService.WsWriteMessage(ws, "err", err.Error())
				continue
			}
		}
	}()
}

// handleMsg 处理用户的提问
func (api chatApi) handleMsg(chatDto ams.ChatInDto, ws *websocket.Conn) (err error) {
	t := checkMsgType(chatDto)
	switch t {
	case "inst":
		var pin ams.PluginInstruct
		arrs := strings.Split(chatDto.Question, " ")
		if len(arrs) < 1 {
			err = fmt.Errorf("入参不合法，in:[%v]", chatDto)
			return
		}
		pin.Cmd = arrs[0]
		pin.Args = arrs[1:]
		pin.Env = ams.ClientPluginFolder
		inst := ams.TcpInstruction{
			InsCode:    ams.InsCode.ExecutePlugin,
			InsContent: utils.Obj2Str(pin),
		}
		m, b := dao.Cache.GetClient(chatDto.ClientId)
		if !b {
			err = fmt.Errorf("设备不存在")
			return
		}
		err = tcp.Writer(m.UniqueCode, inst)
		if err != nil {
			return err
		}
		// 循环读取miao client 响应
		now := time.Now().Unix()
		for range time.Tick(time.Second) {
			val, ok := dao.ResCache.Load(fmt.Sprintf("%d_%s", chatDto.ClientId, ams.ResCode.ExecutePlugin))
			if ok {
				err = service.DsService.WsWriteMessage(ws, "resq", val.(string))
			}
			if time.Now().Unix()-now > 10 {
				err = service.DsService.WsWriteMessage(ws, "err", "响应超时")
				break
			}
		}
	case "llm":
		err = service.DsService.Call2(chatDto.Question, ws)
		if err != nil {
			return err
		}
	default:
		err = fmt.Errorf("入参不合法，in:[%v]", chatDto)
		return
	}
	return err
}

// checkMsgType 判定用户的输入应该怎么处理，例如，inst-指令就直接发送给客户端，自然语言就交给AI处理。
func checkMsgType(chatDto ams.ChatInDto) (str string) {
	if !chatDto.IsAi {
		str = "inst"
		return
	}
	// todo 调用大模型检查用户输入是什么类型，这里先做简易检查
	if isChineseFirstChar(chatDto.Question) {
		str = "llm"
	} else {
		str = "inst"
	}
	return
}
func isChineseFirstChar(s string) bool {
	if len(s) == 0 {
		return false // 空字符串直接返回false
	}
	firstRune := []rune(s)[0]                 // 转换为rune处理多字节字符
	return unicode.Is(unicode.Han, firstRune) // 检查是否在汉字Unicode范围内
}
